Abraxus's Blog

justCTF that's not crypto Write Up

Details:

Points: 500

Jeopardy style CTF

Category: Reversing

Write up:

This challenge gave me a .pyc file so I knew that I would need to use uncompyle:

uncompyle6 checker.pyc 
# uncompyle6 version 3.7.4
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.8.6 (default, Sep 25 2020, 09:36:53) 
# [GCC 10.2.0]
# Embedded file name: checker.py
# Compiled at: 2021-01-30 10:41:40
# Size of source mod 2**32: 50109 bytes
from random import randint

def make_correct_array(s):
    from itertools import accumulate
    s = map(ord, s)
    s = accumulate(s)
    return [x * 69684751861829721459380039 for x in s]


def validate(a, xs):

    def poly(a, x):
        value = 0
        for ai in a:
            value *= x
            value += ai

        return value

    if len(a) != len(xs) + 1:
        return False
    else:
        for x in xs:
            value = poly(a, x)
            if value != 24196561:
                return False

        return True


if __name__ == '__main__':
    a = [...]
    a = [ai * 4919 for ai in a]
    flag_str = input('flag: ').strip()
    flag = make_correct_array(flag_str)
    if validate(a, flag):
        print('Yes, this is the flag!')
        print(flag_str)
    else:
        print('Incorrect, sorry. :(')
# okay decompiling checker.pyc

The array (a) was massive so I shortened with ..., After seeing this I copied the python and put it in a file.

I ran a few tests and found out that a had a length of 58. Looking into the validate function I saw that this meant that the flag would need to be 57 characters long.

I then decided that my best course of action would be to simply use the python code to semi-brute force the correct values:

from random import randint

def make_correct_array(s):
    from itertools import accumulate
    s = map(ord, s)
    s = accumulate(s)
    return [x * 69684751861829721459380039 for x in s]


def validate(a, xs):

    def poly(a, x):
        value = 0
        for ai in a:
            value *= x
            value += ai

        return value

    for x in xs:
        value = poly(a, x)
        if value != 24196561:
            return False

    return True


if __name__ == '__main__':
    a = [...]
    a = [ai * 4919 for ai in a]

    flag_str = "justCTF{"

    while len(flag_str) < 57:
        i = 32
        while i < 127:
            print(flag_str + chr(i))
            flag = make_correct_array(flag_str + chr(i))
            if (validate(a, flag)):
                print("correct:     " + chr(i))
                flag_str += chr(i)
            i += 1

    print(flag_str)

I had done some testing so I knew that first part of the flag was justCTF{ which was the flag format. I then modified the validate function so that it no longer cared about the length of the input and instead only checked if it was correct.

I then went through for the length of the flag and added each possible char to the end of the string and "hashed" the string using their equation. I then checked each combination until I got the correct character, at which point I went to the next one.

The program then spit out the following flag:

justCTF{this_is_very_simple_flag_afer_so_big_polynomails}